#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include "pool.h"

#define STEP	2

static void *admin_job(void *arg);
static void *worker_job(void *arg);

int pool_init(pool_t **mypool, int capacity)
{
	pool_t *me = NULL;
	int i;
	int err;

	me = malloc(sizeof(pool_t));
	if (NULL == me)
		return -errno; // int ret = pool_init(); if (ret < 0) {strerror(-ret)}
	me->workers = calloc(capacity, sizeof(pthread_t));
	if (NULL == me->workers) {
		free(me);
		return -errno;
	}
	queue_init(&me->task_queue, MAXJOB, sizeof(task_t));
	me->max_threads = capacity;
	me->min_free_threads = MIN_FREETHR_NR;
	me->max_free_threads = MAX_FREETHR_NR;
	me->busy_threads = 0;
	me->live_threads = me->min_free_threads;
	pthread_mutex_init(&me->mut_pool, NULL);
	pthread_mutex_init(&me->mut_busy, NULL);
	pthread_cond_init(&me->queue_not_empty, NULL);
	pthread_cond_init(&me->queue_not_full, NULL);
	me->exit_threads = 0;
	me->shutdown = 0;

	// 创建管理者线程
	err = pthread_create(&me->admin_tid, NULL, admin_job, me);
	if (err) {
		free(me->workers);
		free(me);
		return -err;
	}

	// 创建线程池中最少free线程
	for (i = 0; i < me->min_free_threads; i++) {
		err = pthread_create(me->workers + i, NULL, worker_job, me);
		if (err) {
			free(me->workers);
			free(me);
			return -err;
		}
		// 线程分离
		pthread_detach((me->workers)[i]);
	}

	*mypool = me;

	return 0;
}

// 找到工作线程数组中空闲的位置

static int __get_free_pos(pthread_t *jobs, int n)
{
	int i;

	for (i = 0; i < n; i++) {
		// 检测线程是否存在
		if (0 == pthread_kill(jobs[i], 0))
			return i;
	}
	return -1;
}

// 管理者线程函数
static void *admin_job(void *arg)
{
	/*
		周期性查看线程池中busy的线程个数和free的线程个数，适当增减线程
	    例如1s一次	
		while (1) {
			// 拿到线程池的互斥量
			// 获取busy_cnt, free_cnt
			// free_cnt > MAX_FREETHR_NR 减少2(例如)
			// free_cnt == 0 增加2
			sleep(1);
		}

		问题:如何减少线程？
			方式1：取消
			方式2：自杀机制
				exit_threads 增加数值,发送queue_not_empty通知

	 */
	pool_t *mypool = arg;
	int i, pos;
	int free_cnt, busy_cnt;

	while (1) {
		pthread_mutex_lock(&mypool->mut_pool);	
		if (mypool->shutdown) {
			pthread_mutex_unlock(&mypool->mut_pool);
			break;
		}
		pthread_mutex_lock(&mypool->mut_busy);
		busy_cnt = mypool->busy_threads;
		pthread_mutex_unlock(&mypool->mut_busy);
		free_cnt = mypool->live_threads - busy_cnt;	

		// 减少
		if (free_cnt >= mypool->max_free_threads + STEP) {
			mypool->exit_threads = STEP;
			for (i = 0; i < STEP; i++) 
				pthread_cond_signal(&mypool->queue_not_empty);
		}
		// 增加
		if (busy_cnt == mypool->live_threads && mypool->live_threads < mypool->max_threads) {
			for (i = 0; i < STEP; i++) {
				pos = __get_free_pos(mypool->workers, mypool->max_threads);
				if (-1 == pos) {
					// 没有位置了
					fprintf(stderr, "[%d]__get_free_pos() failed\n", __LINE__);	
				}
			accept_socket = accept(tcp_socket, (void *)&caddr, &caddr_len);
			if(accept_socket < 0) {
				perror("accept():");
				close(tcp_socket);
				exit(1);
			}
				pthread_create(mypool->workers + pos, NULL, worker_job, mypool);
				pthread_detach((mypool->workers)[pos]);
				mypool->live_threads++;
			}
		}
		// 测试语句---》打印线程池中线程的个数
		for (i = 0; i < mypool->busy_threads; i++) {
			write(1, "O", 1);
		}
		for (i = 0; i < mypool->live_threads - mypool->busy_threads; i++)
			write(1, "X", 1);
		write(1, "\n", 1);

		pthread_mutex_unlock(&mypool->mut_pool);	
		sleep(1);
	}

	pthread_exit(0);
}

// 工作线程的函数
static void *worker_job(void *arg)
{
	/*
	   循环
	   		抢锁---》判断任务队列是否为空
			空
				解锁等待queue_not_empty通知
				通知来了
					情况1: 池关闭了
					情况2：exit_threads>0 终止
					情况3: 任务队列真的来任务了，出队,busy个数增加了，做任务，任务做完了，循环

	 */
	pool_t *mypool = arg;
	task_t mytask;

	while (1) {
		pthread_mutex_lock(&mypool->mut_pool);	
		if (queue_is_empty(mypool->task_queue)) {
			pthread_cond_wait(&mypool->queue_not_empty, &mypool->mut_pool);
		}
		if (mypool->shutdown) {
			pthread_mutex_unlock(&mypool->mut_pool);
			break;
		}
		if (mypool->exit_threads > 0) {
			mypool->exit_threads--;
			pthread_mutex_unlock(&mypool->mut_pool);
			break;
		}
		// 任务来了
		queue_deq(mypool->task_queue, &mytask);	
		pthread_cond_signal(&mypool->queue_not_full);
		pthread_mutex_unlock(&mypool->mut_pool);
		// 做任务--->busy
		pthread_mutex_lock(&mypool->mut_busy);
		mypool->busy_threads++;
		pthread_mutex_unlock(&mypool->mut_busy);

		(mytask.job)(mytask.arg);
		pthread_mutex_lock(&mypool->mut_busy);
		mypool->busy_threads--;
		pthread_mutex_unlock(&mypool->mut_busy);
	}

	pthread_exit(0);
}

int pool_add_task(pool_t *mypool, const task_t *t)
{
	pthread_mutex_lock(&mypool->mut_pool);
	while (queue_is_full(mypool->task_queue)) {
		pthread_cond_wait(&mypool->queue_not_full, &mypool->mut_pool);
	}
	queue_enq(mypool->task_queue, t);
	pthread_cond_signal(&mypool->queue_not_empty);
	pthread_mutex_unlock(&mypool->mut_pool);

	return 0;
}

void pool_destroy(pool_t *mypool)
{
	pthread_mutex_lock(&mypool->mut_pool);			
	mypool->shutdown = 1;
	pthread_cond_broadcast(&mypool->queue_not_empty);
	pthread_mutex_unlock(&mypool->mut_pool);			

	sleep(1); // 线程分离，不会合，阻塞1s为了等线程得到shutdown

	free(mypool->workers);
	queue_destroy(&mypool->task_queue);
	pthread_mutex_destroy(&mypool->mut_pool);
	pthread_mutex_destroy(&mypool->mut_busy);
	pthread_cond_destroy(&mypool->queue_not_empty);
	pthread_cond_destroy(&mypool->queue_not_full);
	free(mypool);
}
